<!DOCTYPE html>
<html lang="zh_CN">
<head>
    <meta charset="UTF-8">
    <title>入参说明</title>
    <base href="/">
    <script src="js/common/jquery.js"></script>
    <script src="js/common/common-functions.js"></script>
    <script src="css/bootstrap/js/bootstrap.bundle.min.js"></script>
    <link href="css/bootstrap/css/bootstrap.min.css" rel="stylesheet">
    <link href="css/common.css" rel="stylesheet">
    <style>
        pre {
            max-width: 100%;
        }
    </style>
</head>
<body>
<nav class="navbar  common-nav-margin-bottom navbar-expand-lg bg-primary">
    <div class="container">
        <a href="/">
            <img src="asserts/common/mybatis-logo.png" alt="Bootstrap" width="90" height="24">
        </a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavAltMarkup"
                aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarNavAltMarkup">
            <div class="navbar-nav">
                <a class="nav-link" href="/">Home</a>
            </div>
        </div>

    </div>
</nav>
<div class="container page-layout">
    <aside class="aside-menu">
        <ul class="list-unstyled">
            <li><a class="aside-menu-link" href="javascript:void(0) "
                   onclick="scrollToElementById('section-0')">简介</a></li>
            <li><a class="aside-menu-link" href="javascript:void(0) "
                   onclick="scrollToElementById('section-1')">接口方法参数为多个</a></li>
            <li>
                <a class="aside-menu-link" href="javascript:void(0) "
                   onclick="scrollToElementById('section-2')">接口方法参数为一个基本类型</a></li>
            <li>
                <a class="aside-menu-link" href="javascript:void(0) "
                   onclick="scrollToElementById('section-3')">接口方法参数一个自定义类型的</a></li>
            <li>
                <a class="aside-menu-link" href="javascript:void(0) "
                   onclick="scrollToElementById('section-4')">常见错误</a></li>
        </ul>
    </aside>
    <main style="overflow: auto">
        <h1>参数说明</h1>
        <h2 id="section-0">简介</h2>
        <p class="intent-2">
            大多数情况，执行一个sql,无论是查询还是修改，都会向sql 传递参数，这一节讲的是怎么在mapper 文件中使用调用java
            接口方法时传入的参数。
        </p>
        <p class="intent-2 emphasize">
            这一节中的所有说明都是基于jdk8以上 并且编译时保留方法参数元数据的前提下的（javac -parameters），如果不是，那么所有涉及使用参数名字的地方都不可用
        </p>

        <p class="intent-2">验证这一节的内容，可以在 <code>org.apache.ibatis.executor.BaseExecutor</code>类的 <code>update
        </code>方法和 <code>query</code>方法中debug
        </p>

        <h2 id="section-1">接口方法参数为多个</h2>
        <div class="small-light-height-pre can-max">
        <pre id="searchRoleNamePre">
            List&lt;RoleInfo> query(String id, String name, RoleInfo role);
        </pre>
        </div>
        <p class="intent-2">如上面的方法定义，有3个参数， 那么在mapper中可以使用的参数分别是 <code>id, name, role, param1, param2, param3</code>,
            所以可以看出mapper中访问java入参，可以使用java方法的参数名字和 <code>param</code>序列。 因为 role 是一个自定义类型，还可以使用 #{role.属性名}的方式访问对象内容的属性值
        </p>
        <div class=" mb-3 row">
            <label for="searchRoleName" class="col-2 col-form-label" style="text-align: right">名字</label>
            <div class="col-4">
                <input type="text" class="form-control" id="searchRoleName">
            </div>
            <div class="col-6">
                <button type="button" class="btn btn-primary" id="searchRoleNameBtn">查询</button>
            </div>
        </div>

        <h2 id="section-2">接口方法参数为一个基本类型</h2>
        <p class="intent-2">这种情况就更简单了，在mapper中随便写一个名字就可以了，因为java方法入参只有一个值，mybatis 只会将那一个参数的值放在 sql 参数位置上</p>
        <h2 id="section-3">接口方法参数一个自定义类型的</h2>
        <pre>
            public class UserDetail {
                private long id;
                private String userId;
                private Sex sex;
                private Date birthday;
                private int level;

            // getter / setter
            }
            public interface UserDetailMapper {

                int insertUserDetail(UserDetail detail);
            }
        </pre>
        <pre>
            UPDATE user_detail t SET
                t.user_id = #{userId, jdbcType=VARCHAR},
                t.sex = #{sex, jdbcType=NUMERIC},
                t.sex_code = #{sexCode, jdbcType=VARCHAR},
                t.birthday = #{birthday, jdbcType=TIMESTAMP},
                t.level = #{level, jdbcType=NUMERIC},
            WHERE t.id = #{id, jdbcType=VARCHAR}
        </pre>
        <p class="intent-2"> 这种情况可以直接使用入参对象的属性名访问，而不用写成 <code>#{detail.userId}</code>这种形式</p>

        <h2 id="section-4">常见错误</h2>

        <h3> Parameter 'roleName' not found. Available parameters are [name, id, param1, param2]</h3>
        <p class="intent-2">这是mapper中使用的参数，或者参数对象中的属性不存在</p>
        <h3>参数的jdbcType</h3>
        <p>在插入，更新可以为null的字段的时候， jdbcType 最好要写上，否则可能会报错，这个和数据库有关</p>
        <p>如果有以下错误：</p>
        <pre>
            nested exception is org.apache.ibatis.type.TypeException: Could not set parameters for mapping: ParameterMapping{property='hospitalId', mode=IN, javaType=class java.lang.String, jdbcType=null, numericScale=null, resultMapId='null', jdbcTypeName='null', expression='null'}. Cause: org.apache.ibatis.type.TypeException: Error setting null for parameter #1 with JdbcType OTHER . Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. Cause: java.sql.SQLException: 无效的列类型: 1111
        </pre>
        <p>也要将jdbcType 写好</p>

    </main>
</div>
<script>
    $(function () {
        document.querySelector('#searchRoleNameBtn').addEventListener('click', searchByName)
    });

    function searchByName() {
        const roleName = document.querySelector("#searchRoleName").value
        $.ajax('/role/query', {
            type: 'get',
            data: {roleName: roleName},
            success: function (res) {
                document.querySelector("#searchRoleNamePre").appendChild(document.createTextNode(JSON.stringify(res, null, 2)))
            },
            error: function () {

            },
        })
    }
</script>
</body>
</html>
